package com.CST.service.impl;

import com.CST.bo.BaseInfoBO;
import com.CST.common.api.ResultObject;
import com.CST.dto.BaseCostDTO;
import com.CST.dto.DateDTO;
import com.CST.entity.*;
import com.CST.mapper.cst.*;
import com.CST.mapper.dataplatform.BdDepartmentMapper;
import com.CST.mapper.dataplatform.BdEnumdetailMapper;
import com.CST.mapper.dataplatform.BdOrganizationMapper;
import com.CST.service.IBaseCostService;
import com.CST.service.IBaseSecondSubSService;
import com.CST.service.ICostDataService;
import com.CST.service.IEtlDepreciationDetailSplitService;
import com.CST.util.ExcelTransfer;
import com.CST.util.PageHelperTool;
import com.CST.vo.*;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class BaseCostServiceImpl implements IBaseCostService {

    @Autowired
    private BaseCostMapper baseCostMapper;

    @Autowired
    private BdOrganizationMapper bdOrganizationMapper;

    @Autowired
    private BdEnumdetailMapper bdEnumdetailMapper;

    @Autowired
    private BdDepartmentMapper bdDepartmentMapper;

    @Autowired
    private CostDataMapper costDataMapper;

    @Autowired
    private   RuleCompelamortizationMapper  ruleCompelamortizationMapper;
    @Autowired
    private BaseInComeMapper baseInComeMapper;
    @Autowired
    private  EtlDepreciationDetailSplitMapper etlDepreciationDetailSplitMapper;

    @Autowired
    private AmortizationDataMapper amortizationDataMapper;

    @Autowired
    private ICostDataService costDataService;

    @Autowired
    private EtlAcSalaryMapper etlAcSalaryMapper;

    @Autowired
    private EtlDepreciationDetailMapper etlDepreciationDetailMapper;

    @Autowired
    private EtlMzrcMapper etlMzrcMapper;

    @Autowired
    private EtlZyrcMapper etlZyrcMapper;

    @Autowired
    private EtlCwsMapper etlCwsMapper;

    @Autowired
    private EtlAccvouchMapper etlAccvouchMapper;
    @Autowired
    private BaseSecondSubSMapper baseSecondSubSMapper;
    @Autowired
    private  BaseSecondSubMapper baseSecondSubMapper;
    @Autowired
    private IBaseSecondSubSService baseSecondSubSService;
    @Override
    public ResultObject getAllBaseCostByDate(DateDTO dateDTO) {
        List<BaseCost> sumBaseCostList = baseCostMapper.getAllBaseCostByDate(dateDTO);
        return ResultObject.successReturn(sumBaseCostList);
    }

    //原代码:适合场景科室不产生成本
//    @Override
//    public ResultObject listBaseCostGroupDept(DateDTO dateDTO) {
//        List<ReportBaseCostVO> reportBaseCostVOList = new ArrayList<>();
//        List<BdDepartment> bdDepartmentList = bdDepartmentMapper.selectList(null);
//        List<BaseCostVO> baseCostVOList = baseCostMapper.listBaseCostWithPDept(dateDTO, null);
//        // 获取所有父级科室编码
//        List<String> pDeptCodeList = baseCostVOList.stream()
//                .map(t -> t.getPDeptCode())
//                .distinct()
//                .collect(Collectors.toList());
//        for (String pDeptCode : pDeptCodeList) {
//            ReportBaseCostVO reportBaseCostVO = new ReportBaseCostVO();
//            reportBaseCostVO.setDeptCode(pDeptCode);
//            if (pDeptCode.equals("BBBBBBBBBB")) {
//                reportBaseCostVO.setDeptName("未关联科室");
//            } else {
//                BdDepartment bdDepartment = bdDepartmentList.stream()
//                        .filter(t -> pDeptCode.equals(t.getDeptCode()))
//                        .findFirst()
//                        .orElse(null);
//                reportBaseCostVO.setDeptName(bdDepartment.getDeptName());
//            }
//            // 获取所有相应pDeptCode的成本数据
//            List<BaseCostVO> costVOList = baseCostVOList.stream()
//                    .filter(t -> pDeptCode.equals(t.getPDeptCode()))
//                    .collect(Collectors.toList());
//            for (BaseCostVO baseCostVO : costVOList) {
//                BaseCost baseCost = new BaseCost();
//                BeanUtils.copyProperties(baseCostVO, baseCost);
//                this.packageAccountWithBaseCost(reportBaseCostVO, baseCost);
//            }
//            reportBaseCostVOList.add(reportBaseCostVO);
//        }
//        reportBaseCostVOList = reportBaseCostVOList.stream()
//                .sorted(Comparator.comparing(ReportBaseCostVO::getDeptCode))
//                .collect(Collectors.toList());
//        return ResultObject.successReturn(reportBaseCostVOList);
//    }

    @Override
    public ResultObject listBaseCostGroupDept(DateDTO dateDTO) {
        try {
            List<ReportBaseCostVO> reportBaseCostVOList = new ArrayList<>();
            List<BdDepartment> bdDepartmentList = bdDepartmentMapper.selectList(null);
            List<BaseCostVO> baseCostVOList = baseCostMapper.listBaseCostWithPDept(dateDTO, null);
            // 获取所有父级科室编码
            List<String> pDeptCodeList = baseCostVOList.stream()
                    .map(t -> t.getPDeptCode())
                    .distinct()
                    .collect(Collectors.toList());
            for (String pDeptCode : pDeptCodeList) {
                ReportBaseCostVO reportBaseCostVO = new ReportBaseCostVO();
                reportBaseCostVO.setDeptCode(pDeptCode);
                BdDepartment bdDepartment = bdDepartmentList.stream()
                        .filter(t -> pDeptCode.equals(t.getDeptCode()))
                        .findFirst()
                        .orElse(null);
                reportBaseCostVO.setDeptName(bdDepartment.getDeptName());
                // 获取所有相应pDeptCode的成本数据
                List<BaseCostVO> costVOList = baseCostVOList.stream()
                        .filter(t -> pDeptCode.equals(t.getPDeptCode()))
                        .collect(Collectors.toList());
                for (BaseCostVO baseCostVO : costVOList) {
                    BaseCost baseCost = new BaseCost();
                    BeanUtils.copyProperties(baseCostVO, baseCost);
                    this.packageAccountWithBaseCost(reportBaseCostVO, baseCost);
                }
                reportBaseCostVOList.add(reportBaseCostVO);
            }
            reportBaseCostVOList = reportBaseCostVOList.stream()
                    .sorted(Comparator.comparing(ReportBaseCostVO::getDeptCode))
                    .collect(Collectors.toList());
            return ResultObject.successReturn(reportBaseCostVOList);
        }
        catch (Exception ex)
        {
            int a=0;
        }
        return ResultObject.successReturn(null);
    }

    /**
     * 根据父级科室代码查询子类的各项成本
     *
     * @param dateDTO
     * @param pDeptCode
     * @return
     */
    @Override
    public ResultObject listBaseCostByPDeptCode(DateDTO dateDTO, String pDeptCode) {
        List<ReportBaseCostVO> reportBaseCostVOList = new ArrayList<>();
        List<BdDepartment> bdDepartmentList = bdDepartmentMapper.selectList(null);
        List<BaseCostVO> baseCostVOList = baseCostMapper.listBaseCostWithPDept(dateDTO, pDeptCode);
        // 获取所有科室编码
        List<String> deptCodeList = baseCostVOList.stream()
                .map(t -> t.getDeptCode())
                .distinct()
                .collect(Collectors.toList());
        for (String deptCode : deptCodeList) {
            ReportBaseCostVO reportBaseCostVO = new ReportBaseCostVO();
            reportBaseCostVO.setDeptCode(deptCode);
            BaseCostVO data = baseCostVOList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .findFirst()
                    .orElse(null);
            reportBaseCostVO.setDeptName(data.getDeptName());
            // 获取所有子科室编码对应的成本数据
            List<BaseCostVO> costVOList = baseCostVOList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .collect(Collectors.toList());
            for (BaseCostVO baseCostVO : costVOList) {
                BaseCost baseCost = new BaseCost();
                BeanUtils.copyProperties(baseCostVO, baseCost);
                this.packageAccountWithBaseCost(reportBaseCostVO, baseCost);
            }
            reportBaseCostVOList.add(reportBaseCostVO);
        }
        reportBaseCostVOList = reportBaseCostVOList.stream()
                .sorted(Comparator.comparing(ReportBaseCostVO::getDeptCode))
                .collect(Collectors.toList());
        return ResultObject.successReturn(reportBaseCostVOList);
    }

    /**
     * 根据传入的父级id查询药品费用
     *
     * @param dateDTO
     * @param pDeptCode
     * @return
     */
    @Override
    public ResultObject listCostByPDeptCodeAndUnitCode(DateDTO dateDTO, String pDeptCode) {
        List<BdDepartment> childrenss = new ArrayList<>();
        if ("102".equals(dateDTO.getUnitCode())) {
            List<BdDepartment> childrens = bdDepartmentMapper.getChildrens(pDeptCode);
            List<String> lstDept = childrens.stream()
                    .map(BdDepartment::getDeptCode)
                    .distinct()
                    .collect(Collectors.toList());
            //高值材料
            dateDTO.setLstDept(lstDept);
            List<HygienicMaterialsVO> advancedMaterials = etlAccvouchMapper.getAdvancedMaterials(dateDTO);
            if (childrens.size() == 0) {
                BdDepartment info = new BdDepartment();
                info.setDeptCode(pDeptCode);
                childrens.add(info);
            }
            childrenss.addAll(childrens);
            List<HygienicMaterialsVO> list = costDataMapper.selectCostItem(dateDTO, childrenss);
            list.addAll(advancedMaterials);
            return ResultObject.successReturn(list);
        } else {
            return ResultObject.successReturn(costDataMapper.listCostByPDeptCodeAndUnitCode(dateDTO, pDeptCode));
        }
    }

    @Override
    public ResultObject listMaterialsCategorySummary(DateDTO dateDTO, String deptCode) {
        BdDepartment searchInfo =new BdDepartment();
        searchInfo.setDeptCode(deptCode);
        List<BdDepartment> deptList = bdDepartmentMapper.getDepartmentSource(searchInfo);
        List<HygienicMaterialsVO> list = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(deptList))
        {
            list = costDataMapper.selectCostItem(dateDTO, deptList);
        }
        return ResultObject.successReturn(list);
    }

    @Override
    public ResultObject listCostInfoByPDeptCodeAndUnitCode(DateDTO dateDTO, String pDeptCode) {
        List<BaseInfoBO> data = costDataMapper.listCostByPDeptCodeAndUnitCodeInfo(dateDTO, pDeptCode);

        List<BaseInfoBO> list2 = data.stream()
                .filter(e -> "自筹科研经费".equals(e.getCInvName()))
                .collect(Collectors.toList());
        List<BaseInfoBO> list3 = data.stream()
                .filter(e -> "出库价格调整".equals(e.getCInvName()))
                .collect(Collectors.toList());
        List<BaseInfoBO> list1 = data.stream()
                .filter(e -> !"自筹科研经费".equals(e.getCInvName()) && !"出库价格调整".equals(e.getCInvName()))
                .collect(Collectors.toList());
        //新加需求
        list2.forEach(item->{
            item.setCInvName("科研经费");
        });
        data.clear();
        data.addAll(list1);
        data.addAll(list2);
        data.addAll(list3);
        String s = data.stream().map(BaseInfoBO::getAllMoney).reduce(BigDecimal.ZERO, BigDecimal::add).toString();
        return ResultObject.success(data, s);
    }

    /**
     * 根据传入的科室id查询药品明细
     *
     * @param dateDTO
     * @param deptCode
     * @return
     */
    @Override
    public ResultObject listCostByDeptCodeAndUnitCode(DateDTO dateDTO, String deptCode) {
        List<CostDataInfo> costDataInfoList = costDataMapper.listCostByDeptCodeAndUnitCode(dateDTO, deptCode);
        List<BdDepartment> bdDepartments = bdDepartmentMapper.selectList(null);
        BdDepartment bdDepartment = bdDepartments.stream()
                .filter(t -> deptCode.equals(t.getDeptCode()))
                .findFirst()
                .orElse(null);
        costDataInfoList.stream().map(t -> {
            t.setDeptCode(deptCode);
            t.setDeptName(bdDepartment.getDeptName());
            return true;
        }).collect(Collectors.toList());
        return ResultObject.successReturn(costDataInfoList);
    }

    /**
     * 根据传入的年月范围按成本项目汇总
     *
     * @param dateDTO
     * @return
     */
    @Override
    public ResultObject listBaseCostWithCostItem(DateDTO dateDTO) {
        List<ReportAmortizationDataVO> baseCostWithCostItemList = baseCostMapper.listBaseCostWithCostItem(dateDTO);
        PageInfo<ReportAmortizationDataVO> reportAmortizationDataVOPageInfo = PageHelperTool.excutePageInfo(
                baseCostWithCostItemList,
                dateDTO.getPageNum(),
                dateDTO.getPageSize());
        return ResultObject.successReturn(reportAmortizationDataVOPageInfo);
    }

    @Override
    public ResultObject listCostWithPDept(DateDTO dateDTO) {
        List<ReportAmortizationDataVO> costAndInComeVOList = new ArrayList<>();
        // 会计分类
        List<BdEnumdetail> accountInfoList = bdEnumdetailMapper.listAllAccount();
        List<BdDepartment> bdDepartmentList = bdDepartmentMapper.selectList(null);
        // 收入数据
        List<InSourceVO> inSourceVOList = baseInComeMapper.listInComeWithPDept(dateDTO);
        // 源成本数据
        List<ReportBaseCostVO> srcBaseCostList = baseCostMapper.listCostWithPDeptAndCostType(dateDTO);
        List<BdOrganization> bdOrganizationList = bdOrganizationMapper.listParentDeptGroup("1");
        // 间接成本数据
        List<ReportAmortizationDataVO> indirectCostList = amortizationDataMapper.listIndirectCostWithPDept(dateDTO);
        List<String> pDeptCodeList = bdOrganizationList.stream()
                .map(t -> t.getPDeptCode())
                .distinct()
                .collect(Collectors.toList());
        // 循环科室
        for (String deptCode : pDeptCodeList) {
            ReportAmortizationDataVO costAndInComeVO = new ReportAmortizationDataVO();
            costAndInComeVO.setDeptCode(deptCode);
            costAndInComeVO.setDeptName(bdDepartmentList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .findFirst()
                    .orElse(null)
                    .getDeptName());
            // 本执本开
            List<InSourceVO> thisBillThisExeList = inSourceVOList.stream()
                    .filter(t -> deptCode.equals(t.getBillPDeptCode()) && deptCode.equals(t.getExePDeptCode()))
                    .collect(Collectors.toList());
            costAndInComeVO.setThisBillThisExe(thisBillThisExeList.stream()
                    .map(InSourceVO::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            // 本执他开
            List<InSourceVO> otherBillThisExeList = inSourceVOList.stream()
                    .filter(t -> !deptCode.equals(t.getBillPDeptCode()) && deptCode.equals(t.getExePDeptCode()))
                    .collect(Collectors.toList());
            costAndInComeVO.setOtherBillThisExe(otherBillThisExeList.stream()
                    .map(InSourceVO::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            // 他执本开
            List<InSourceVO> thisBillOtherExeList = inSourceVOList.stream()
                    .filter(t -> deptCode.equals(t.getBillPDeptCode()) && !deptCode.equals(t.getExePDeptCode()))
                    .collect(Collectors.toList());
            costAndInComeVO.setThisBillOtherExe(thisBillOtherExeList.stream()
                    .map(InSourceVO::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            for (BdEnumdetail accountInfo : accountInfoList) {
                costAndInComeVO = setCostWithAccount(costAndInComeVO,
                        accountInfo.getEdCode(),
                        deptCode,
                        srcBaseCostList,
                        indirectCostList,
                        true);
            }
            costAndInComeVOList.add(costAndInComeVO);
        }

        return ResultObject.successReturn(costAndInComeVOList);
    }

    @Override
    public ResultObject listCostWithDept(DateDTO dateDTO) {
        List<ReportAmortizationDataVO> costAndInComeVOList = new ArrayList<>();
        // 会计分类
        List<BdEnumdetail> accountInfoList = bdEnumdetailMapper.listAllAccount();
        List<BdDepartment> bdDepartmentList = bdDepartmentMapper.selectList(null);
        // 收入数据
        List<InSourceVO> inSourceVOList = baseInComeMapper.listInComeWithPDept(dateDTO);
        // 源成本数据
        List<ReportBaseCostVO> srcBaseCostList = baseCostMapper.listCostWithPDeptAndCostType(dateDTO);
        List<BdOrganization> bdOrganizationList = bdOrganizationMapper.listParentDeptGroup("1");
        // 间接成本数据
        List<ReportAmortizationDataVO> indirectCostList = amortizationDataMapper.listIndirectCostWithPDept(dateDTO);
        List<String> deptCodeList = bdOrganizationList.stream()
                .map(t -> t.getDeptCode())
                .distinct()
                .collect(Collectors.toList());
        for (String deptCode : deptCodeList) {
            ReportAmortizationDataVO costAndInComeVO = new ReportAmortizationDataVO();
            costAndInComeVO.setDeptCode(deptCode);
            BdDepartment bdDepartment = bdDepartmentList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .findFirst()
                    .orElse(null);
            if (bdDepartment != null) {
                costAndInComeVO.setDeptName(bdDepartment.getDeptName());
            }
            // 本执本开
            List<InSourceVO> thisBillThisExeList = inSourceVOList.stream()
                    .filter(t -> deptCode.equals(t.getBillDeptCode()) && deptCode.equals(t.getExecutiveDeptCode()))
                    .collect(Collectors.toList());
            costAndInComeVO.setThisBillThisExe(thisBillThisExeList.stream()
                    .map(InSourceVO::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            // 本执他开
            List<InSourceVO> otherBillThisExeList = inSourceVOList.stream()
                    .filter(t -> !deptCode.equals(t.getBillDeptCode()) && deptCode.equals(t.getExecutiveDeptCode()))
                    .collect(Collectors.toList());
            costAndInComeVO.setOtherBillThisExe(otherBillThisExeList.stream()
                    .map(InSourceVO::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            // 他执本开
            List<InSourceVO> thisBillOtherExeList = inSourceVOList.stream()
                    .filter(t -> deptCode.equals(t.getBillDeptCode()) && !deptCode.equals(t.getExecutiveDeptCode()))
                    .collect(Collectors.toList());
            costAndInComeVO.setThisBillOtherExe(thisBillOtherExeList.stream()
                    .map(InSourceVO::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            for (BdEnumdetail accountInfo : accountInfoList) {
                costAndInComeVO = setCostWithAccount(costAndInComeVO,
                        accountInfo.getEdCode(),
                        deptCode,
                        srcBaseCostList,
                        indirectCostList,
                        false);
            }
            costAndInComeVOList.add(costAndInComeVO);
        }
        return ResultObject.successReturn(costAndInComeVOList);
    }

    @Override
    public ResultObject listBaseCostDeptByDate(DateDTO dateDTO) {

        List<BaseAllCostVO> baseAllCostVOS = baseCostMapper.listBaseCostDeptByDate(dateDTO);

        PageInfo<BaseAllCostVO> baseAllCostVOPageInfo = PageHelperTool.excutePageInfo(baseAllCostVOS, dateDTO.getPageNum(), dateDTO.getPageSize());
        return  ResultObject.success(baseAllCostVOPageInfo);
    }
    @Autowired
    private ExcelTransfer<BaseAllCostVO> excelTransfers;
    @Override
    public void exportExcel10(HttpServletResponse response, DateDTO dateDTO) throws IOException {
        List<BaseAllCostVO> baseAllCostVOS = baseCostMapper.listBaseCostDeptByDate(dateDTO);
        excelTransfers.exportExcel(response, baseAllCostVOS, "各科室全成本表", "sheet1", BaseAllCostVO.class);
    }

    @Override
    public void insertBaseCost(CostDataInfo costDataInfo) {
        costDataInfo.setMonth(String.valueOf(Integer.parseInt(costDataInfo.getMonth())));
        // 删除
        baseCostMapper.deleteByYearAndMonth(Integer.parseInt(costDataInfo.getYear()),
                Integer.parseInt(costDataInfo.getMonth()));
        List<BaseCost> costList = costDataMapper.listBaseCostData(costDataInfo);
        // 查询人员经费明细成本
        List<BaseCost> baseCostWithSalary = etlAcSalaryMapper.listBaseCostWithSalary(costDataInfo);
        // 冲抵成本
        List<BaseCost> baseCostWithOffset = etlAcSalaryMapper.listBaseCostWithOffset(costDataInfo);
        // 统计所有成本
        costList.addAll(baseCostWithSalary);
        costList.addAll(baseCostWithOffset);
        Integer year = Integer.parseInt(costDataInfo.getYear());
        int total1 = costList.size();//为防止插入字符超过最大数,分批插入
        int fromIndex1 = 0;
        List<BaseCost> insertList1 = new ArrayList<>();
        for (int i = 0; i < costList.size(); i++) {
            BaseCost item = costList.get(i);
            fromIndex1++;
            insertList1.add(item);
            if (fromIndex1 % 20 == 0 && fromIndex1 <= total1) {
                baseCostMapper.insertBaseCost(insertList1, year);
                insertList1 = new ArrayList<>();
            }
        }
        if (CollectionUtils.isNotEmpty(insertList1)) {
            baseCostMapper.insertBaseCost(insertList1, year);
        }

        // 查询折旧明细和无形资产摊销明细总额
        // 先删后插
        DateDTO dateDTO = new DateDTO();
        dateDTO.setYear(Integer.parseInt(costDataInfo.getYear()));
        dateDTO.setMonth(Integer.parseInt(costDataInfo.getMonth()));
        etlDepreciationDetailMapper.deleteOffsetByDate(dateDTO);
        EtlDepreciationDetail zc057 = this.packageOffset(dateDTO, "ZC057");
        // 固定资产折旧
        BigDecimal fixedAmount = costList.stream()
                .filter(t -> "104".equals(t.getAccountCode()))
                .map(t -> t.getAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        zc057.setValue(zc057.getValue().add(fixedAmount));
        etlDepreciationDetailMapper.insert(zc057);
        EtlDepreciationDetail zc058 = this.packageOffset(dateDTO, "ZC058");
        // 无形资产摊销
        BigDecimal intangibleAmount = costList.stream()
                .filter(t -> "105".equals(t.getAccountCode()))
                .map(t -> t.getAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        zc058.setValue(zc058.getValue().add(intangibleAmount));
        etlDepreciationDetailMapper.insert(zc058);
    }

    @Autowired
    private IEtlDepreciationDetailSplitService iEtlDepreciationDetailSplitService;
    @Override
    public void insertBaseCostDel(CostDataInfo costDataInfo) {
        costDataInfo.setMonth(String.valueOf(Integer.parseInt(costDataInfo.getMonth())));
        // 删除
        baseCostMapper.deleteDelByYearAndMonth(Integer.parseInt(costDataInfo.getYear()),
                Integer.parseInt(costDataInfo.getMonth()));
        //获取拆分的明细
        List<BaseCost> costList = costDataMapper.listBaseCostData(costDataInfo);

        // 查询人员经费明细成本
        List<BaseCost> baseCostWithSalary = etlAcSalaryMapper.listBaseCostWithSalaryDEL(costDataInfo);
        // 冲抵成本
        List<BaseCost> baseCostWithOffset = etlAcSalaryMapper.listBaseCostWithOffset(costDataInfo);
        // 统计所有成本
        costList.addAll(baseCostWithSalary);
        costList = this.splitBaseCost(costList,costDataInfo);
        costList.addAll(baseCostWithOffset);
        Integer year = Integer.parseInt(costDataInfo.getYear());
        int total1 = costList.size();//为防止插入字符超过最大数,分批插入
        int fromIndex1 = 0;
        List<BaseCost> insertList1 = new ArrayList<>();
        for (int i = 0; i < costList.size(); i++) {
            BaseCost item = costList.get(i);
            fromIndex1++;
            insertList1.add(item);
            if (fromIndex1 % 20 == 0 && fromIndex1 <= total1) {
                baseCostMapper.insertBaseCostDel(insertList1, year);
                insertList1 = new ArrayList<>();
            }
        }
        if (CollectionUtils.isNotEmpty(insertList1)) {
            baseCostMapper.insertBaseCostDel(insertList1, year);
        }
        // 查询折旧明细和无形资产摊销明细总额
        // 先删后插
        DateDTO dateDTO = new DateDTO();
        dateDTO.setYear(Integer.parseInt(costDataInfo.getYear()));
        dateDTO.setMonth(Integer.parseInt(costDataInfo.getMonth()));
        etlDepreciationDetailSplitMapper.deleteOffsetByDate(dateDTO);
        List<EtlDepreciationDetailSplit> etlDepreciationDetailSplitList = this.splitSetlDepreciationDetailSplit(dateDTO);


        int total = etlDepreciationDetailSplitList.size();//为防止插入字符超过最大数,分批插入
        if (total > 0) {
            int fromIndex = 0;
            List<EtlDepreciationDetailSplit> insertList = new ArrayList<>();
            for (int i = 0; i < etlDepreciationDetailSplitList.size(); i++) {
                EtlDepreciationDetailSplit item = etlDepreciationDetailSplitList.get(i);
                fromIndex++;
                insertList.add(item);
                if (fromIndex % 20 == 0 && fromIndex <= total) {
                    iEtlDepreciationDetailSplitService.saveBatch(insertList);
                    insertList = new ArrayList<>();
                }
            }
            if (CollectionUtils.isNotEmpty(insertList)) {
                iEtlDepreciationDetailSplitService.saveBatch(insertList);
            }

        }
        //卫生材料费
        baseSecondSubSMapper.deleteByDate(dateDTO);
        List<BaseSecondSubS> baseSecondSubS = this.copyBaseSecondSub(dateDTO);

        int total2 = baseSecondSubS.size();//为防止插入字符超过最大数,分批插入
        if (total2 > 0) {
            int fromIndex = 0;
            List<BaseSecondSubS> insertList = new ArrayList<>();
            for (int i = 0; i < baseSecondSubS.size(); i++) {
                BaseSecondSubS item = baseSecondSubS.get(i);
                fromIndex++;
                insertList.add(item);
                if (fromIndex % 20 == 0 && fromIndex <= total2) {
                    baseSecondSubSService.saveBatch(insertList);
                    insertList = new ArrayList<>();
                }
            }
            if (CollectionUtils.isNotEmpty(insertList)) {
                baseSecondSubSService.saveBatch(insertList);
            }

        }
        etlAccvouchMapper.delByOperDtime(dateDTO);
        List<EtlAccvouch> etlAccvouches = this.splitEtlAccvouch(dateDTO);
        int total3 = etlAccvouches.size();//为防止插入字符超过最大数,分批插入
        if (total3 > 0) {
            int fromIndex = 0;
            List<EtlAccvouch> insertList = new ArrayList<>();
            for (int i = 0; i < etlAccvouches.size(); i++) {
                EtlAccvouch item = etlAccvouches.get(i);
                fromIndex++;
                insertList.add(item);
                if (fromIndex % 20 == 0 && fromIndex <= total3) {
                    etlAccvouchMapper.insertBaseCost(insertList,year);
                    insertList = new ArrayList<>();
                }
            }
            if (CollectionUtils.isNotEmpty(insertList)) {
                etlAccvouchMapper.insertBaseCost(insertList,year);
            }

        }

    }

    @Autowired
    private BdEnumdetailMapper mapper;

    @Override
    public List<BaseCost> listBaseCost(CostDataInfo costDataInfo) {
        List<BaseCost> costDataInfoList = baseCostMapper.listBaseCost(costDataInfo);
        return costDataInfoList;
    }


    @Override
    public boolean saveOrUpdateBaseCost(BaseCostDTO dto) {
        BaseCost baseCost = new BaseCost();
        BeanUtils.copyProperties(dto, baseCost);
        baseCost.setExtraB(dto.getRemark());
        BdEnumdetail enumdetail = new BdEnumdetail();
        enumdetail.setEdCode(dto.getCostItemCode());
        LocalDate time = dto.getTime();
        int year = time.getYear();
        int month = time.getMonth().getValue();
        baseCost.setYear(year);
        baseCost.setMonth(month);
        List<BdEnumdetail> list = mapper.getEnumDetailSource(enumdetail);
        if (list.size() == 1) {
            BdEnumdetail bdEnumdetail = list.get(0);
            baseCost.setAccountCode(bdEnumdetail.getEdExtraFirstCode());
            baseCost.setAccountName(bdEnumdetail.getEdExtraFirstDescription());
        }
        if (baseCost.getId() != null) {
            int oldYear = dto.getOldTime().getYear();
            if (oldYear != baseCost.getYear()) {
                removeBaseCost(baseCost.getId(), oldYear);
                baseCost.setId(null);
            }
        }
        return baseCost.getId() == null ? baseCostMapper.insertBaseCostOne(baseCost) : baseCostMapper.updateBaseCostOne(
                baseCost);
    }

    @Override
    public boolean removeBaseCost(long id, int year) {
        return baseCostMapper.deleteBaseCostOne(id, year);
    }

    /**
     * 科室经营分析
     *
     * @param dateDTO
     * @param pDeptCode
     * @return
     */
    @Override
    public List<ReportBusinessVO> listCostAndInComeByPDept(DateDTO dateDTO, String pDeptCode) {
        List<ReportBusinessVO> reportBusinessVOList = new ArrayList<>();
        List<BdDepartment> bdDepartmentList = bdDepartmentMapper.selectList(null);
        // 获取父级科室指定的收入数据
        List<BaseInCome> baseInComeList = baseInComeMapper.listBaseInComeByDateAndPDept(dateDTO, pDeptCode);
        BigDecimal inComeAmount = baseInComeList.stream()
                .map(t -> t.getAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 获取指定时间范围和父级科室的成本
        List<BaseCostVO> baseCostVOList = baseCostMapper.listBaseCostWithPDept(dateDTO, pDeptCode);
        BigDecimal costAmount = baseCostVOList.stream()
                .map(t -> t.getAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 计算门诊人次
        List<EtlMzrc> mzrcList = etlMzrcMapper.listMzrcByDateAndPDept(dateDTO, pDeptCode);
        BigDecimal mzrcNumber = mzrcList.stream().map(t -> t.getRegisterNum()).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 计算住院人次
        List<EtlZyrc> zyrcList = etlZyrcMapper.listZyrcByDateAndPDept(dateDTO, pDeptCode);
        BigDecimal zyrcNumber = zyrcList.stream().map(t -> t.getOutNum()).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 固定床位
        List<EtlCws> cwsList = etlCwsMapper.listCwsByDept(dateDTO, pDeptCode);
        // 计算收益
        BigDecimal proceedsAmount = inComeAmount.subtract(costAmount);
        // 本期
        ReportBusinessVO thisBusiness = new ReportBusinessVO();
        thisBusiness.setDeptName("本期");
        thisBusiness.setInCome(inComeAmount);
        thisBusiness.setCost(costAmount);
        thisBusiness.setProceeds(proceedsAmount);
        thisBusiness.setMzrcNumber(mzrcNumber);
        thisBusiness.setCyNumber(zyrcNumber);
        reportBusinessVOList.add(thisBusiness);
        // 预算
        ReportBusinessVO budgetBusiness = new ReportBusinessVO();
        budgetBusiness.setDeptName("预算");
        reportBusinessVOList.add(budgetBusiness);
        // 差异
        ReportBusinessVO differenceBusiness = new ReportBusinessVO();
        BeanUtils.copyProperties(thisBusiness, differenceBusiness);
        differenceBusiness.setDeptName("差异");
        differenceBusiness.setMzrcNumber(mzrcNumber);
        differenceBusiness.setCyNumber(zyrcNumber);
        reportBusinessVOList.add(differenceBusiness);
        // 计算各科室的收入、成本和收益
        List<BdOrganization> bdOrganizationList = bdOrganizationMapper.listParentDeptGroup("1");
        List<BdOrganization> pDeptList = bdOrganizationList.stream()
                .filter(t -> pDeptCode.equals(t.getPDeptCode()))
                .collect(Collectors.toList());

        //医技收入统计
        BigDecimal medicalTechnologyInCome =BigDecimal.ZERO;
        for (BdOrganization organization : pDeptList) {
            String deptCode = organization.getDeptCode();
            String deptName = organization.getDeptName();
            ReportBusinessVO reportBusinessVO = new ReportBusinessVO();
            reportBusinessVO.setDeptCode(deptCode);
            reportBusinessVO.setDeptName(deptName);
            // 获取其子科室收入总额
            inComeAmount = baseInComeList.stream()
                    .filter(t -> deptCode.equals(t.getBillDeptCode()) || deptCode.equals(t.getExecutiveDeptCode()))
                    .map(t -> t.getAmount())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 获取子科室成本总额
            costAmount = baseCostVOList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .map(t -> t.getAmount())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 计算收益
            proceedsAmount = inComeAmount.subtract(costAmount);
            reportBusinessVO.setCost(costAmount);
            reportBusinessVO.setInCome(inComeAmount);
            reportBusinessVO.setProceeds(proceedsAmount);
            // 计算门诊人次
            BigDecimal mzrc = mzrcList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .map(t -> t.getRegisterNum())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            reportBusinessVO.setMzrcNumber(mzrc);
            // 计算出院人次
            BigDecimal cyrc = zyrcList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .map(t -> t.getOutNum())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            reportBusinessVO.setCyNumber(cyrc);
            // 计算平均住院天数
            BigDecimal avgStay =zyrcList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .map(t -> t.getAvgStay())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            reportBusinessVO.setAvgStay(avgStay.setScale(2, RoundingMode.HALF_UP));
            // 计算床位数
            BigDecimal bedSum = cwsList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .map(t -> t.getBedSum())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            reportBusinessVO.setBedSum(bedSum);
            // 计算医技收入和医技人次
            BdDepartment bdDepartment = bdDepartmentList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()))
                    .findFirst()
                    .orElse(null);
            if (bdDepartment != null && "02".equals(bdDepartment.getDeptTypeId())) {
                reportBusinessVO.setMedicalTechnologyInCome(inComeAmount);
                medicalTechnologyInCome =medicalTechnologyInCome.add(inComeAmount);
                int size = baseInComeList.stream()
                        .filter(t -> bdDepartment.getDeptCode().equals(t.getExecutiveDeptCode()))
                        .collect(Collectors.toList())
                        .size();
                reportBusinessVO.setMedicalTechnologyNumber(size);
            }
            reportBusinessVOList.add(reportBusinessVO);
        }

        thisBusiness.setMedicalTechnologyInCome(medicalTechnologyInCome);
        return reportBusinessVOList;
    }

    @Autowired
    private ExcelTransfer<ReportBaseCostVO> excelTransfer;

    @Override
    public void exportExcel(HttpServletResponse response, DateDTO dateDTO) {
        List<ReportBaseCostVO> data = (List<ReportBaseCostVO>) listBaseCostGroupDept(dateDTO).getData();
        data.forEach(e -> {
            if ("AAAAAAAAAA".equals(e.getDeptCode())) {
                e.setDeptCode("9998");
            }
        });
        excelTransfer.exportExcel(response, data, "名字", "sheet", ReportBaseCostVO.class);
    }

    @Autowired
    private BaseSalaryServiceImpl baseSalaryService;

    @Autowired
    private RdCostsalaryrelationServiceImpl rdCostsalaryrelationService;

    @Autowired
    private EtlDepreciationDetailServiceImpl etlDepreciationDetailService;

    @Override
    public void exportExcelDepartment(HttpServletResponse response, DateDTO dateDTO, String pDeptCode) throws IOException {
        List<ExcelVO> excel = new ArrayList<>();

        // 科室详情head
        List<String> reportBaseOld = new ArrayList<>();
        reportBaseOld.add("科室代码");
        reportBaseOld.add("科室名称");
        reportBaseOld.add("人员经费");
        reportBaseOld.add("药品费");
        reportBaseOld.add("卫生材料费");
        reportBaseOld.add("固定资产折旧费");
        reportBaseOld.add("无形资产摊销");
        reportBaseOld.add("提取医疗风险基金");
        reportBaseOld.add("其他费用");
        reportBaseOld.add("总计");
        // 科室详情data
        List<List<Object>> reportBaseData = new ArrayList<>();
        List<ReportBaseCostVO> reportBaseCost = (List<ReportBaseCostVO>) listBaseCostByPDeptCode(dateDTO,
                pDeptCode).getData();
        reportBaseCost.forEach(e -> {
            List<Object> list = new ArrayList<>();
            list.add(e.getDeptCode());
            list.add(e.getDeptName());
            list.add(e.getPersonnel());
            list.add(e.getDrug());
            list.add(e.getSanitaryMaterials());
            list.add(e.getFixed());
            list.add(e.getIntangible());
            list.add(e.getRisk());
            list.add(e.getOther());
            reportBaseData.add(list);
        });
        List<List<String>> reportBase = getHead(reportBaseOld);
        excel.add(ExcelVO.builder().sheet("科室代码").listsHead(reportBase).listsData(reportBaseData).build());

        // 人员经费一级明细
        List<ReportBaseSalaryVO> reportBaseSalary = baseSalaryService.listSalaryWithExtraByPDeptCode(dateDTO,
                pDeptCode);
        // 薪酬head
        List<String> salaryHeadOld = rdCostsalaryrelationService.listCostItemByDate(dateDTO)
                .stream()
                .map(RdCostsalaryrelation::getCostItemName)
                .collect(Collectors.toList());
        List<String> salaryHeadInfo = rdCostsalaryrelationService.listCostItemByDate(dateDTO)
                .stream()
                .map(RdCostsalaryrelation::getCostItemCode)
                .collect(Collectors.toList());
        // 薪酬data
        List<List<Object>> salaryData = new ArrayList<>();
        reportBaseSalary.forEach(e -> {
            List<ReportSalaryDetailVO> reportSalaryDetail = baseSalaryService.listSalaryDetailByDateAndPDeptAndDept(
                    dateDTO,
                    pDeptCode,
                    e.getDeptCode());
            if (reportSalaryDetail.size() > 0) {
                reportSalaryDetail.forEach(c -> {
                    List<Object> list = new ArrayList<>();
                    list.add(c.getDeptCode());
                    list.add(c.getDeptName());
                    list.add(c.getEmpId());
                    list.add(c.getEmpName());
                    Map<String, BigDecimal> accParam = c.getAccParam();
                    List<Object> param = new ArrayList<>();
                    salaryHeadInfo.forEach(key -> param.add(accParam.get(key)));
                    list.addAll(param);
                    salaryData.add(list);
                });
            }
        });
        salaryHeadOld.add(0, "科室代码");
        salaryHeadOld.add(1, "科室名称");
        salaryHeadOld.add(2, "工号");
        salaryHeadOld.add(3, "姓名");
        List<List<String>> salaryHead = getHead(salaryHeadOld);
        excel.add(ExcelVO.builder().sheet("人员经费-薪酬").listsHead(salaryHead).listsData(salaryData).build());

        // 其他head
        List<String> salaryOtherOld = new ArrayList<>();
        salaryOtherOld.add("科室代码");
        salaryOtherOld.add("科室名称");
        salaryOtherOld.add("成本项目名称");
        salaryOtherOld.add("金额");
        salaryOtherOld.add("摘要");
        // 其他data
        List<List<Object>> salaryOtherData = new ArrayList<>();
        reportBaseSalary.forEach(e -> {
            List<ReportBaseSalaryVO> reportBaseSalaryOther =
                    baseSalaryService.listPerformanceDetailByDateAndPDeptAndDept(
                    dateDTO,
                    pDeptCode,
                    e.getDeptCode());
            reportBaseSalaryOther.forEach(c -> {
                List<Object> list = new ArrayList<>();
                list.add(c.getDeptCode());
                list.add(c.getDeptName());
                list.add(c.getCostItemName());
                list.add(c.getAmount());
                list.add(c.getExtraB());
                salaryOtherData.add(list);
            });
        });
        List<List<String>> salaryOtherHead = getHead(salaryOtherOld);
        excel.add(ExcelVO.builder()
                .sheet("人员经费-其他")
                .listsHead(salaryOtherHead)
                .listsData(salaryOtherData)
                .build());

        // 药品费详情head
        List<String> drugOld = new ArrayList<>();
        drugOld.add("科室代码");
        drugOld.add("科室名称");
        drugOld.add("成本项目名称");
        drugOld.add("金额");
        // 药品费详情data
        List<List<Object>> drugData = new ArrayList<>();
        dateDTO.setUnitCode("103");
        List<CostDataInfo> drug = (List<CostDataInfo>) listCostByPDeptCodeAndUnitCode(dateDTO, pDeptCode).getData();
        drug.forEach(e -> {
            List<Object> list = new ArrayList<>();
            list.add(e.getDeptCode());
            list.add(e.getDeptName());
            list.add(e.getCostItemName());
            list.add(e.getAmount());
            drugData.add(list);
        });
        List<List<String>> drugHead = getHead(drugOld);
        excel.add(ExcelVO.builder().sheet("药品费详情").listsHead(drugHead).listsData(drugData).build());

        // 卫生材料head
        List<String> healthHeadOld = new ArrayList<>();
        healthHeadOld.add("科室代码");
        healthHeadOld.add("科室名称");
        healthHeadOld.add("名称");
        healthHeadOld.add("单价");
        healthHeadOld.add("数量");
        healthHeadOld.add("总价");
        healthHeadOld.add("类型");
        // 卫生材料data
        List<List<Object>> healthData = new ArrayList<>();
        dateDTO.setUnitCode("102");
        List<HygienicMaterialsVO> health = (List<HygienicMaterialsVO>) listCostByPDeptCodeAndUnitCode(dateDTO,
                pDeptCode).getData();
        health.forEach(e -> {
            dateDTO.setUnitCode(e.getCharge());
            List<BaseInfoBO> data = (List<BaseInfoBO>) listCostInfoByPDeptCodeAndUnitCode(dateDTO,
                    e.getDeptCode()).getData();
            data.forEach(c -> {
                List<Object> list = new ArrayList<>();
                list.add(e.getDeptCode());
                list.add(e.getDeptName());
                list.add(c.getCInvName());
                list.add(c.getPrice());
                list.add(c.getNumber());
                list.add(c.getAllMoney());
                list.add(Objects.equals(e.getCharge(), "N") ? "不可收费" : "可收费");
                healthData.add(list);
            });
        });
        List<List<String>> healthHead = getHead(healthHeadOld);
        excel.add(ExcelVO.builder().sheet("卫生材料费").listsHead(healthHead).listsData(healthData).build());

        // 折旧资产head
        List<String> depreciationHeadOld = new ArrayList<>();
        depreciationHeadOld.add("核算单元代码");
        depreciationHeadOld.add("核算单元名称");
        depreciationHeadOld.add("固定资产编码");
        depreciationHeadOld.add("固定资产名称");
        depreciationHeadOld.add("启用日期");
        depreciationHeadOld.add("原值");
        depreciationHeadOld.add("折旧月段");
        depreciationHeadOld.add("折旧额");
        // 折旧资产data
        List<List<Object>> depreciationData = new ArrayList<>();
        dateDTO.setUnitCode("ZC057");
        List<DepreciationDetailVO> depreciationDetail = etlDepreciationDetailService.listByPDeptCode(dateDTO,
                pDeptCode);
        depreciationDetail.forEach(e -> {
            List<Object> list = new ArrayList<>();
            list.add(e.getDeptcode());
            list.add(e.getDeptname());
            list.add(e.getCardnum());
            list.add(e.getCardname());
            list.add(e.getUsestartdate());
            list.add(e.getOriginalvalue());
            list.add(e.getMonthlimit());
            list.add(e.getValue());
            depreciationData.add(list);
        });
        List<List<String>> depreciationHead = getHead(depreciationHeadOld);
        excel.add(ExcelVO.builder()
                .sheet("固定资产折旧费详情")
                .listsHead(depreciationHead)
                .listsData(depreciationData)
                .build());

        // 无形资产head
        List<String> invisibleHeadOld = new ArrayList<>();
        invisibleHeadOld.add("核算单元代码");
        invisibleHeadOld.add("核算单元名称");
        invisibleHeadOld.add("无形资产代码");
        invisibleHeadOld.add("无形资产名称");
        invisibleHeadOld.add("启用日期");
        invisibleHeadOld.add("原值");
        invisibleHeadOld.add("折旧月段");
        invisibleHeadOld.add("折旧额");
        // 无形资产data
        List<List<Object>> invisibleData = new ArrayList<>();
        dateDTO.setUnitCode("ZC058");
        List<DepreciationDetailVO> invisibleDetail = etlDepreciationDetailService.listByPDeptCode(dateDTO, pDeptCode);
        invisibleDetail.forEach(e -> {
            List<Object> list = new ArrayList<>();
            list.add(e.getDeptcode());
            list.add(e.getDeptname());
            list.add(e.getCardnum());
            list.add(e.getCardname());
            list.add(e.getUsestartdate());
            list.add(e.getOriginalvalue());
            list.add(e.getMonthlimit());
            list.add(e.getValue());
            invisibleData.add(list);
        });
        List<List<String>> invisibleHead = getHead(invisibleHeadOld);
        excel.add(ExcelVO.builder()
                .sheet("无形资产摊销详情")
                .listsHead(invisibleHead)
                .listsData(invisibleData)
                .build());

        // 其他费用head
        List<String> otherHeadOld = new ArrayList<>();
        otherHeadOld.add("科室代码");
        otherHeadOld.add("科室名称");
        otherHeadOld.add("科目");
        otherHeadOld.add("金额");
        otherHeadOld.add("摘要");
        // 其他费用data
        List<List<Object>> otherData = new ArrayList<>();
        dateDTO.setUnitCode("107");
        List<CostDataInfo> other = (List<CostDataInfo>) listCostByPDeptCodeAndUnitCode(dateDTO, pDeptCode).getData();
        other.forEach(e -> {
            List<Object> list = new ArrayList<>();
            list.add(e.getDeptCode());
            list.add(e.getDeptName());
            list.add(e.getCostItemName());
            list.add(e.getAmount());
            list.add(e.getDescription());
            otherData.add(list);
        });
        List<List<String>> otherHead = getHead(otherHeadOld);
        excel.add(ExcelVO.builder().sheet("其他费用详情").listsHead(otherHead).listsData(otherData).build());

        excelTransfer.exportExcel(response, "报表", excel);
    }

    @Override
    public void exportExcel5(HttpServletResponse response, DateDTO dateDTO) throws IOException {
        List<ExcelVO> excel = new ArrayList<>();

        // head
        List<String> headOld = new ArrayList<>();
        headOld.add("年");
        headOld.add("月");
        headOld.add("核算单元代码");
        headOld.add("核算单元名称");
        headOld.add("核算定义代码");
        headOld.add("核算定义名称");
        headOld.add("成本项目编码");
        headOld.add("成本项目名称");
        headOld.add("成本金额");
        // data
        List<List<Object>> otherData = new ArrayList<>();
        List<ReportAmortizationDataVO> baseCostWithCostItemList = baseCostMapper.listBaseCostWithCostItem(dateDTO);
        baseCostWithCostItemList.forEach(e -> {
            List<Object> list = new ArrayList<>();
            list.add(String.valueOf(e.getYear()));
            list.add(String.valueOf(e.getMonth()));
            list.add(e.getDeptCode());
            list.add(e.getDeptName());
            list.add(e.getPDeptCode());
            list.add(e.getPDeptName());
            list.add(e.getCostItemCode());
            list.add(e.getCostItemName());
            list.add(e.getSum());
            otherData.add(list);
        });
        List<List<String>> otherHead = getHead(headOld);
        excel.add(ExcelVO.builder()
                .sheet("各科室直接成本表（按成本项目汇总）")
                .listsHead(otherHead)
                .listsData(otherData)
                .build());

        excelTransfer.exportExcel(response, "各科室直接成本表（按成本项目汇总）", excel);
    }

    @Override
    public void exportExcel7(HttpServletResponse response, DateDTO dateDTO) throws IOException {
        List<ExcelVO> excel = new ArrayList<>();

        // head
        List<String> headOld = new ArrayList<>();
        headOld.add("科室编码");
        headOld.add("科室名称");
        headOld.add("本开本执");
        headOld.add("本执他开");
        headOld.add("本开他执");
        headOld.add("工资直接成本");
        headOld.add("工资间接成本");
        headOld.add("卫生材料直接成本");
        headOld.add("卫生材料间接成本");
        headOld.add("药品费直接成本");
        headOld.add("药品费间接成本");
        headOld.add("固定资产折旧直接成本");
        headOld.add("固定资产折旧间接成本");
        headOld.add("无形资产摊销直接成本");
        headOld.add("无形资产摊销间接成本");
        headOld.add("提取医疗风险基金直接成本");
        headOld.add("提取医疗风险基金间接成本");
        headOld.add("其他费用直接成本");
        headOld.add("其他费用间接成本");
        // data
        List<List<Object>> otherData = new ArrayList<>();
        List<ReportAmortizationDataVO> data = (List<ReportAmortizationDataVO>) listCostWithPDept(dateDTO).getData();
        data.forEach(e -> {
            List<Object> list = new ArrayList<>();
            list.add(e.getDeptCode());
            list.add(e.getDeptName());
            list.add(e.thisBillThisExe);
            list.add(e.otherBillThisExe);
            list.add(e.thisBillOtherExe);
            list.add(e.personnel);
            list.add(e.indirectPersonnel);
            list.add(e.sanitaryMaterials);
            list.add(e.indirectSanitaryMaterials);
            list.add(e.drug);
            list.add(e.indirectDrug);
            list.add(e.fixed);
            list.add(e.indirectFixed);
            list.add(e.directIntangible);
            list.add(e.indirectIntangible);
            list.add(e.directRisk);
            list.add(e.indirectRisk);
            list.add(e.other);
            list.add(e.indirectOther);
            otherData.add(list);
        });
        List<List<String>> otherHead = getHead(headOld);
        excel.add(ExcelVO.builder()
                .sheet("核算科室收入成本汇总表（核算定义）")
                .listsHead(otherHead)
                .listsData(otherData)
                .build());

        excelTransfer.exportExcel(response, "核算科室收入成本汇总表（核算定义）", excel);
    }

    @Override
    public void exportExcel8(HttpServletResponse response, DateDTO dateDTO) throws IOException {
        List<ExcelVO> excel = new ArrayList<>();

        // head
        List<String> headOld = new ArrayList<>();
        headOld.add("科室编码");
        headOld.add("科室名称");
        headOld.add("本开本执");
        headOld.add("本执他开");
        headOld.add("本开他执");
        headOld.add("工资直接成本");
        headOld.add("工资间接成本");
        headOld.add("卫生材料直接成本");
        headOld.add("卫生材料间接成本");
        headOld.add("药品费直接成本");
        headOld.add("药品费间接成本");
        headOld.add("固定资产折旧直接成本");
        headOld.add("固定资产折旧间接成本");
        headOld.add("无形资产摊销直接成本");
        headOld.add("无形资产摊销间接成本");
        headOld.add("提取医疗风险基金直接成本");
        headOld.add("提取医疗风险基金间接成本");
        headOld.add("其他费用直接成本");
        headOld.add("其他费用间接成本");
        // data
        List<List<Object>> otherData = new ArrayList<>();
        List<ReportAmortizationDataVO> data = (List<ReportAmortizationDataVO>) listCostWithDept(dateDTO).getData();
        data.forEach(e -> {
            List<Object> list = new ArrayList<>();
            list.add(e.getDeptCode());
            list.add(e.getDeptName());
            list.add(e.thisBillThisExe);
            list.add(e.otherBillThisExe);
            list.add(e.thisBillOtherExe);
            list.add(e.personnel);
            list.add(e.indirectPersonnel);
            list.add(e.sanitaryMaterials);
            list.add(e.indirectSanitaryMaterials);
            list.add(e.drug);
            list.add(e.indirectDrug);
            list.add(e.fixed);
            list.add(e.indirectFixed);
            list.add(e.directIntangible);
            list.add(e.indirectIntangible);
            list.add(e.directRisk);
            list.add(e.indirectRisk);
            list.add(e.other);
            list.add(e.indirectOther);
            otherData.add(list);
        });
        List<List<String>> otherHead = getHead(headOld);
        excel.add(ExcelVO.builder()
                .sheet("核算科室收入成本汇总表（核算单元）")
                .listsHead(otherHead)
                .listsData(otherData)
                .build());

        excelTransfer.exportExcel(response, "核算科室收入成本汇总表（核算单元）", excel);
    }

    @Autowired
    private ExcelTransfer<DeptBaseCostVO> excelTransferss;
    @Override
    public void exportExcel11(HttpServletResponse response, DateDTO dateDTO) {
        List<DeptBaseCostVO> baseAllCostVOS = this.getDeptBaseCost(dateDTO);
        excelTransferss.exportExcel(response, baseAllCostVOS, "季度科室成本表", "sheet1", DeptBaseCostVO.class);

    }

    @Override
    public List<DeptBaseCostVO> getDeptBaseCost(DateDTO dateDTO) {
        Integer starYear = dateDTO.getStarYear();
        Integer starMonth = dateDTO.getStarMonth();
        Integer endYear = dateDTO.getEndYear();
        Integer endMonth = dateDTO.getEndMonth();
        DecimalFormat decimalFormat = new DecimalFormat("00");
        dateDTO.setStarTime(starYear+decimalFormat.format(starMonth));
        dateDTO.setEndTime(endYear+decimalFormat.format(endMonth));
        List<DeptBaseCostVO> deptBaseCostVOS = new ArrayList<>();
        List<ReportBaseCostVO> data = (List<ReportBaseCostVO>) listBaseCostGroupDept(dateDTO).getData();
        List<DeptBaseCostVO> deptBaseCost = baseCostMapper.getDeptBaseCost(dateDTO);
        for (ReportBaseCostVO datum : data) {
            DeptBaseCostVO deptBaseCostVO1 = new DeptBaseCostVO();
            DeptBaseCostVO deptBaseCostVO = deptBaseCost.stream().filter(s -> s.getDeptCode().equals(datum.getDeptCode())).findFirst().orElse(null);
            BeanUtils.copyProperties(datum,deptBaseCostVO1);
            if (deptBaseCostVO !=null){
                deptBaseCostVO1.setFixed1(deptBaseCostVO.getFixed1());
                deptBaseCostVO1.setPersonnel1(deptBaseCostVO.getPersonnel1());
                deptBaseCostVO1.setSanitaryMaterials1(deptBaseCostVO.getSanitaryMaterials1());
                deptBaseCostVO1.setOther1(deptBaseCostVO.getOther1());
            }
            deptBaseCostVOS.add(deptBaseCostVO1);
        }

        return deptBaseCostVOS;
    }

    public static List<List<String>> getHead(List<String> old) {
        List<List<String>> head = new ArrayList<>();
        old.forEach(e -> {
            List<String> list = new ArrayList<>();
            list.add(e);
            head.add(list);
        });
        return head;
    }


    /**
     * isParent -> true：父级，false：子级
     *
     * @param accountCode
     * @param deptCode
     * @param srcBaseCostList
     * @param indirectCostList
     * @return
     */
    private ReportAmortizationDataVO setCostWithAccount(ReportAmortizationDataVO dataVO, String accountCode,
                                                        String deptCode, List<ReportBaseCostVO> srcBaseCostList,
                                                        List<ReportAmortizationDataVO> indirectCostList,
                                                        boolean isParent) {
        BigDecimal amount = BigDecimal.ZERO;
        BigDecimal indirect = BigDecimal.ZERO;
        if (isParent) {
            // 获取相应的直接成本
            amount = srcBaseCostList.stream()
                    .filter(t -> deptCode.equals(t.getPDeptCode()) && accountCode.equals(t.getAccountCode()))
                    .map(t -> t.getSum())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            amount.add(indirectCostList.stream()
                    .filter(t -> deptCode.equals(t.getPDeptCode()) && accountCode.equals(t.getAccountCode()))
                    .map(t -> t.getDirectCost())
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            // 获取相应的间接成本
            indirect = indirectCostList.stream()
                    .filter(t -> deptCode.equals(t.getPDeptCode()) && accountCode.equals(t.getAccountCode()))
                    .map(t -> t.getIndirectCost())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        } else {
            amount = srcBaseCostList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()) && accountCode.equals(t.getAccountCode()))
                    .map(t -> t.getSum())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            amount.add(indirectCostList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()) && accountCode.equals(t.getAccountCode()))
                    .map(t -> t.getDirectCost())
                    .reduce(BigDecimal.ZERO, BigDecimal::add));
            indirect = indirectCostList.stream()
                    .filter(t -> deptCode.equals(t.getDeptCode()) && accountCode.equals(t.getAccountCode()))
                    .map(t -> t.getIndirectCost())
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        switch (accountCode) {
            case "101":
                dataVO.setPersonnel(amount);
                dataVO.setIndirectPersonnel(indirect);
                break;
            case "102":
                dataVO.setSanitaryMaterials(amount);
                dataVO.setIndirectSanitaryMaterials(indirect);
                break;
            case "103":
                dataVO.setDrug(amount);
                dataVO.setIndirectDrug(indirect);
                break;
            case "104":
                dataVO.setFixed(amount);
                dataVO.setIndirectFixed(indirect);
                break;
            case "105":
                dataVO.setIntangible(amount);
                dataVO.setIndirectIntangible(indirect);
                break;
            case "106":
                dataVO.setRisk(amount);
                dataVO.setIndirectRisk(indirect);
                break;
            case "107":
                dataVO.setOther(amount);
                dataVO.setIndirectOther(indirect);
                break;
        }
        return dataVO;
    }

    /**
     * 根据会计科目复制直接直接成本
     * 用于直接成本报表
     */
    private ReportBaseCostVO packageAccountWithBaseCost(ReportBaseCostVO reportBaseCostVO, BaseCost baseCost) {
        String accountCode = baseCost.getAccountCode();
        BigDecimal amount = baseCost.getAmount() == null ? new BigDecimal(0) : baseCost.getAmount();
        switch (accountCode) {
            case "101":
                reportBaseCostVO.setPersonnel(reportBaseCostVO.getPersonnel().add(amount));
                break;
            case "102":
                reportBaseCostVO.setSanitaryMaterials(reportBaseCostVO.getSanitaryMaterials().add(amount));
                break;
            case "103":
                reportBaseCostVO.setDrug(reportBaseCostVO.getDrug().add(amount));
                break;
            case "104":
                reportBaseCostVO.setFixed(reportBaseCostVO.getFixed().add(amount));
                break;
            case "105":
                reportBaseCostVO.setIntangible(reportBaseCostVO.getIntangible().add(amount));
                break;
            case "106":
                reportBaseCostVO.setRisk(reportBaseCostVO.getRisk().add(amount));
                break;
            case "107":
                reportBaseCostVO.setOther(reportBaseCostVO.getOther().add(amount));
                break;
        }
        reportBaseCostVO.setSum(reportBaseCostVO.getSum().add(amount));
        return reportBaseCostVO;
    }

    /**
     * 根据传入的时间+CostItemCode计算总额
     * 并生成相应的冲抵数据插入到表里
     * deptCode统一为9998
     */
    private EtlDepreciationDetail packageOffset(DateDTO dateDTO, String costItemCode) {
        EtlDepreciationDetail etlDepreciationDetail = new EtlDepreciationDetail();
        etlDepreciationDetail.setCostitemcode(costItemCode);
        etlDepreciationDetail.setDeptcode("9998");
        String costItemName = "";
        switch (costItemCode) {
            case "ZC057":
                costItemName = "固定资产折旧";
                break;
            case "ZC058":
                costItemName = "无形资产摊销";
                break;
            default:
                costItemName = "其他";
                break;
        }
        etlDepreciationDetail.setCostitemname(costItemName);
        etlDepreciationDetail.setYear(dateDTO.getYear());
        etlDepreciationDetail.setMonth(dateDTO.getMonth());
        etlDepreciationDetail.setSourcetype("offset");
        List<EtlDepreciationDetail> etlDepreciationDetailList = etlDepreciationDetailMapper.listByDate(dateDTO);
        // 获取总额
        List<EtlDepreciationDetail> detailList = etlDepreciationDetailList.stream()
                .filter(t -> costItemCode.equals(t.getCostitemcode()))
                .collect(Collectors.toList());
        BigDecimal value = detailList.stream().map(t -> t.getValue()).reduce(BigDecimal.ZERO, BigDecimal::add);
        value = value.multiply(BigDecimal.valueOf(-1));
        etlDepreciationDetail.setValue(value);
        return etlDepreciationDetail;
    }

    public List<BaseCost> splitBaseCost( List<BaseCost> costList,CostDataInfo costDataInfo) {
        List<BaseCost> baseCosts = new ArrayList<>();
        List<RuleCompelamortization> compelRule = ruleCompelamortizationMapper.getCompelRule(Integer.parseInt(costDataInfo.getYear()),
                Integer.parseInt(costDataInfo.getMonth()));
        for (BaseCost baseCost : costList) {
            List<RuleCompelamortization> collect = compelRule.stream().filter(t -> t.getDeptcode().equals(baseCost.getDeptCode())).collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(collect)){
                for (RuleCompelamortization ruleCompelamortization : collect) {
                    BaseCost baseCost1 = new BaseCost();
                    BeanUtils.copyProperties(baseCost,baseCost1);
                    baseCost1.setDeptCode(ruleCompelamortization.getTodeptcode());
                    baseCost1.setDeptName(ruleCompelamortization.getTodeptname());
                    baseCost1.setAmount(baseCost.getAmount().multiply(new BigDecimal(ruleCompelamortization.getRulecode())));
                    baseCost1.setExtraA(null);
                    baseCosts.add(baseCost1);
                }

            }else {
                baseCosts.add(baseCost);
            }
        }
        return  baseCosts;
    }


    public List<EtlDepreciationDetailSplit>  splitSetlDepreciationDetailSplit( DateDTO dateDTO ){
        List<EtlDepreciationDetailSplit> etlDepreciationDetailSplitList = new ArrayList<>();
        List<EtlDepreciationDetail> etlDepreciationDetailList = etlDepreciationDetailMapper.listByDate(dateDTO);
        List<RuleCompelamortization> compelRule = ruleCompelamortizationMapper.getCompelRule(dateDTO.getYear(),
                dateDTO.getMonth());
        for (EtlDepreciationDetail etlDepreciationDetail : etlDepreciationDetailList) {
            List<RuleCompelamortization> collect = compelRule.stream().filter(t -> t.getDeptcode().equals(etlDepreciationDetail.getDeptcode())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)){
                for (RuleCompelamortization ruleCompelamortization : collect) {
                    EtlDepreciationDetailSplit etlDepreciationDetailSplit = new EtlDepreciationDetailSplit();
                    BeanUtils.copyProperties(etlDepreciationDetail,etlDepreciationDetailSplit);
                    etlDepreciationDetailSplit.setDeptcode(ruleCompelamortization.getTodeptcode());
                    etlDepreciationDetailSplit.setDeptname(ruleCompelamortization.getTodeptname());
                    etlDepreciationDetailSplit.setValue(etlDepreciationDetail.getValue().multiply(new BigDecimal(ruleCompelamortization.getRulecode())));
                    etlDepreciationDetailSplitList.add(etlDepreciationDetailSplit);
                }
            } else {
                EtlDepreciationDetailSplit etlDepreciationDetailSplit = new EtlDepreciationDetailSplit();
                BeanUtils.copyProperties(etlDepreciationDetail,etlDepreciationDetailSplit);
                etlDepreciationDetailSplitList.add(etlDepreciationDetailSplit);
            }
        }
        return etlDepreciationDetailSplitList;
    }

    public List<BaseSecondSubS> copyBaseSecondSub(DateDTO dateDTO) {
        List<BaseSecondSubS> baseSecondSubS = new ArrayList<>();
        List<BaseSecondSub> baseSecondSubs = baseSecondSubMapper.selectListByYearAndMonth(dateDTO);
        List<RuleCompelamortization> compelRule = ruleCompelamortizationMapper.getCompelRule(dateDTO.getYear(),
                dateDTO.getMonth());
        for (BaseSecondSub baseSecondSub : baseSecondSubs) {
            List<RuleCompelamortization> collect = compelRule.stream().filter(t -> t.getDeptcode().equals(baseSecondSub.getDeptCode())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)){
                for (RuleCompelamortization ruleCompelamortization : collect) {
                    BaseSecondSubS baseSecondSub1 = new BaseSecondSubS();
                    BeanUtils.copyProperties(baseSecondSub,baseSecondSub1);
                    baseSecondSub1.setDeptCode(ruleCompelamortization.getTodeptcode());
                    baseSecondSub1.setAllMoney(( BigDecimal.valueOf(baseSecondSub.getAllMoney()).multiply(new BigDecimal(ruleCompelamortization.getRulecode()))).doubleValue());
                    baseSecondSubS.add(baseSecondSub1);
                }
            }else {
                BaseSecondSubS baseSecondSub1 = new BaseSecondSubS();
                BeanUtils.copyProperties(baseSecondSub,baseSecondSub1);
                baseSecondSubS.add(baseSecondSub1);
            }
        }


        return baseSecondSubS;
    }

    public List<EtlAccvouch> splitEtlAccvouch(DateDTO dateDTO) {

        List<EtlAccvouch> etlAccvouches = new ArrayList<>();
        List<EtlAccvouch> etlAccvouches1 = etlAccvouchMapper.listByDate(dateDTO);

        List<RuleCompelamortization> compelRule = ruleCompelamortizationMapper.getCompelRule(dateDTO.getYear(),
                dateDTO.getMonth());
        for (EtlAccvouch etlAccvouch : etlAccvouches1) {
            List<RuleCompelamortization> collect = compelRule.stream().filter(t -> t.getDeptcode().equals(etlAccvouch.getDeptCode())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)){
                for (RuleCompelamortization ruleCompelamortization : collect) {
                    EtlAccvouch etlAccvouch1 = new EtlAccvouch();
                    BeanUtils.copyProperties(etlAccvouch,etlAccvouch1);
                    etlAccvouch1.setDeptCode(ruleCompelamortization.getTodeptcode());
                    etlAccvouch1.setMc((BigDecimal.valueOf(etlAccvouch.getMc()).multiply(new BigDecimal(ruleCompelamortization.getRulecode()))).doubleValue());
                    etlAccvouch1.setMd((BigDecimal.valueOf(etlAccvouch.getMd()).multiply(new BigDecimal(ruleCompelamortization.getRulecode()))).doubleValue());
                    etlAccvouches.add(etlAccvouch1);
                }
            }else {
                EtlAccvouch etlAccvouch1 = new EtlAccvouch();
                BeanUtils.copyProperties(etlAccvouch,etlAccvouch1);
                etlAccvouches.add(etlAccvouch1);
            }

        }
        return etlAccvouches;
    }


}
